Android — 事件分发机制(二)

前言

上一篇我们其实已经知道事件分发机制的大概内容了,也是参考了郭大叔的两篇博文总结的。但是隐约感觉有点乱,要是真自己说说事件分发机制,又似乎无从谈起。本篇文章则是侧重总结性,在参考一些较新的博文来慢慢阐述,与上一篇最大的不同的是,本篇还是很建议大家阅读的,虽然我很菜。

参考以下:

安卓自定义View进阶-事件分发机制原理

安卓自定义View进阶-事件分发机制详解

事件分发、拦截与消费

类型 相关方法 Activity ViewGroup View
事件分发 dispatchTouchEvent()
事件拦截 onInterceptTouchEvent()
事件消费 onTouchEvent()

从上表可以看出,Activity和View都是没有事件拦截功能的,这是因为:

  • Activity作为原始的事件分发者,如果Activity拦截了事件就会导致整个屏幕都无法相应事件,那么之前给控件注册事件就显得画蛇添足。
  • View作为事件传递的最末端,要么消费掉事件,要么不处理进行回传,根本没必要进行事件拦截。

事件分发流程

事件收集之后最先传递给Activity,然后依次向下传递,大致如下:

1
Activity --> PhoneWindow --> DecorView --> ViewGroup --> ··· --> View

如果最后分发给了View,View也没有处理事件会怎么办?那么事件就会反方向回传,最终传給Activity,如果最后Activity也没有处理,那么事件才会被抛弃:

1
Activity <-- PhoneWindow <-- DecorView <-- ViewGroup <-- ··· <-- View

这就是非常经典的责任链模式 ,如果我能处理就拦截下来自己干,如果处理不了就交给责任链中的下一个对象。

常见事件

先了解一下常见的几种事件,根据面向对象的思想,事件都被封装成了MotionEvent对象,本篇重点不在于此,所以只会涉及几个与手指触摸相关的常见事件:

时间 简介
ACTION_DOWN 手指 初次接触到屏幕 时触发
ACTION_MOVE 手指 在屏幕上滑动 时触发,往往会触发多次
ACTION_UP 手指 离开屏幕 时触发
ACTION_CANCEL 时间 被上层拦截 时触发

事件分发、拦截与消费

类型 相关方法 ViewGroup View
事件分发 dispatchTouchEvent()
事件拦截 onInterceptTouchEvent()
事件消费 onTouchEvent()

dispatchTouchEvent() 是事件分发机制的核心,所有的事件调度都归他管。ViewGroup有很多子View需要管理,需要事件分发也说得过去,但是为什么View也要有事件分发呢?

那是因为View可以注册很多事件监听器:onClick()、onLongClick()、onTouch(),并且View自身也有onTouchEvent()方法,那么多事件方法肯定要有dispatchTouchEvent()来管理咯。

事件调度顺序:

ViewGroup相关

  1. ViewGroup中可能有多个ChildView,如何判断应该分配给哪一个呢?

    把所有ChildView遍历一遍,如果手指触摸点在ChildView区域内就分给这个View。

  2. 当该点的ChildView有重叠时应该如何分配呢?

    当ChildView重叠时,一般会分配给显示在最上面的ChildView。那如何判断哪个是显示在最上面的呢?后面加载的一般会覆盖掉之前的,所以显示在最上面的是最后加载的。

  3. ViewGroup和ChildView同时注册了事件监听器,哪个会先执行?

    事件优先给ChildView,会被ChildView消费掉,ViewGroup不会相应。

  4. 所有事件都应该被同一View消费。

    同一次点击事件只能被一个View消费。View中onClick事件需要同时接受到ACTION_DOWN和ACTION_UP才能触发,如果分配给了不同的View,那么onClick将无法被正确触发。

    Android为了保证所有的事件都是被一个View消费的,对第一次事件(ACTION_DOWN)进行了特殊判断,View只有消费了ACTION_DOWN事件,才能接受到后续的事件(可点击控件默认会消费所有事件),并且会将后续所有事件传递过来,不会再传递给其他View,除非上层View进行了拦截。如果上层View拦截了当前正在处理的事件,会收到一个ACTION_CANCEL,表示当前事件已经结束,后续事件不会再传递过来。

  5. 一次触摸流程中产生事件应被同一个View消费,全部接受或者全部拒绝。

我们一直都向往,面朝大海,春暖花开。 但是几人能做到,心中有爱,四季不败?